package cn.dt.ymcc.service.impl;

import cn.dt.ymcc.CourseFeignClient;
import cn.dt.ymcc.GlobalException;
import cn.dt.ymcc.domain.*;
import cn.dt.ymcc.dto.CourseOrderParamDto;
import cn.dt.ymcc.dto.KillCourseOrderParamDto;
import cn.dt.ymcc.dto.KillPreOrderParamDto;
import cn.dt.ymcc.dto.PayDto;
import cn.dt.ymcc.mapper.CourseOrderMapper;
import cn.dt.ymcc.result.JSONResult;
import cn.dt.ymcc.service.ICourseOrderItemService;
import cn.dt.ymcc.service.ICourseOrderService;
import cn.dt.ymcc.util.AssertUtil;
import cn.dt.ymcc.util.CodeGenerateUtils;
import cn.dt.ymcc.vo.CourseItemVo;
import cn.dt.ymcc.vo.OrderInfoVo;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import org.apache.commons.lang.StringUtils;
import org.apache.rocketmq.client.producer.LocalTransactionState;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.client.producer.TransactionSendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.assertj.core.internal.bytebuddy.implementation.bytecode.Throw;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author whale.dai
 * @since 2022-07-29
 */
@Service
public class CourseOrderServiceImpl extends ServiceImpl<CourseOrderMapper, CourseOrder> implements ICourseOrderService {
    @Autowired
    private RedisTemplate<Object,Object> redisTemplate;
    @Autowired
    private CourseFeignClient courseFeignClient;
    @Autowired
    private ICourseOrderItemService courseOrderItemService;
    @Autowired
    private RocketMQTemplate rocketMQTemplate;
    /**
     * 支付保存
     * 1.参数校验做了
     * 2.token是否有效
     * 3.业务判断，课程不能为空，不能重复等等调用course的feign
     * 4.保存主订单表
     * 5.保存子订单表（算出总金额）
     * 6.修改主订单表的总金额
     *
     * @param dto
     */
    @Override
    public String placeOrder(CourseOrderParamDto dto) {
        //2.token是否有效
        List<Long> courseIds = dto.getCourseIds();
        String strIds = StringUtils.join(courseIds, ",");
        Long loginId = 1L;
        String key = loginId+":"+strIds;
        Object tokenTmp = redisTemplate.opsForValue().get(key);
        AssertUtil.isNotNull(tokenTmp,"token失效");
        AssertUtil.isEquals(dto.getToken(),tokenTmp.toString(),"token不匹配，请重试");
        //3.业务判断，课程不能为空，不能重复等等,用feign调用course服务的获取支付列表展示接口即可
        JSONResult orderInfoObj = courseFeignClient.getOrderInfo(strIds);
        AssertUtil.isNotNull(orderInfoObj,"调用course服务失败啦");
        /**
         * 此处因为调用feign接口，传递数据会发生序列化所以需要转换才能拿到返回的OrderInfoVo对象
         */
        String jsonString = JSON.toJSONString(orderInfoObj.getData());
        OrderInfoVo orderInfoVo = JSONObject.parseObject(jsonString, OrderInfoVo.class);
        /*
        获取到包含Course和CourseMarket的对象
         */
        List<CourseItemVo> courseInfos = orderInfoVo.getCourseInfos();
        CourseOrder courseOrder = new CourseOrder();
        CourseOrderItem courseOrderItem = new CourseOrderItem();
        Date date = new Date();
        for (CourseItemVo courseInfo : courseInfos) {
            Course course = courseInfo.getCourse();
            CourseMarket courseMarket = courseInfo.getCourseMarket();
            //保存主订单方法
            saveCourseOrder(courseOrder,date,loginId,course);
            //保存子订单方法
            saveCourseOrderItem(course,courseOrder,courseOrderItem,courseMarket,date);
            //修改主订单总价格
            courseOrder.setTotalAmount(courseOrderItem.getAmount());
            //修改主订单总订单数
            courseOrder.setTotalCount(courseOrder.getTotalCount()+courseOrderItem.getCount());
            courseOrder.setItem(courseOrderItem);
            //updateById(courseOrder);
            /*
             *将paydto转为 Message类型对象和order相关存入mq，
             *
             */

            PayDto payDto = new PayDto(courseOrder.getTotalAmount(),courseOrder.getPayType(),courseOrder.getId(),courseOrder.getOrderNo(),courseOrder.getUserId(),"额外参数是什么鬼",courseOrder.getTitle());
            Message<String> build = MessageBuilder.withPayload(JSON.toJSONString(payDto)).build();

            //将order信息存入rocketMq中的方法,发送事务消息
            depositRocketMQ(build,courseOrder);
            //发送延迟消息
            delayedMessage(courseOrder);
        }
        //删除redis中的token
        redisTemplate.delete(key);
        return courseOrder.getOrderNo();

    }

    /**
     * mq发送送延迟消息
     */
    private void delayedMessage(CourseOrder courseOrder) {
        try {
            Message<String> message = MessageBuilder.withPayload(courseOrder.getOrderNo()).build();
            SendResult sendResult = rocketMQTemplate.syncSend(
                    "order-delay-topic:order-delay--args",
                    message,
                    1000 * 60 * 30,
                    16);
            SendStatus sendStatus = sendResult.getSendStatus();
            if(sendStatus!=SendStatus.SEND_OK){
                /*
                只要没发送成功就想办法重发或者让工作人员知道
                 */
            }
        } catch (Exception e) {
            e.printStackTrace();
             /*
                只要没发送成功就想办法重发或者让工作人员知道
                 */
        }
    }

    /**
     * 通过订单号查询订单
     * @param orderNo
     */
    @Override
    public CourseOrder selectByOrderNo(String orderNo) {
        Wrapper<CourseOrder> wrapper = new EntityWrapper<>();
        wrapper.eq("order_no",orderNo);
        CourseOrder order = selectOne(wrapper);
        return order;

    }

    /**
     * 将pay和order信息交给mq发送事务消息发送事务消息
     */
    private void depositRocketMQ(Message message,CourseOrder courseOrder) {
        TransactionSendResult result = rocketMQTemplate.sendMessageInTransaction(
                "sever-order",
                "order-topic:order-args",
                message,
                courseOrder
        );
        LocalTransactionState localTransactionState = result.getLocalTransactionState();
       if( result.getSendStatus()!= SendStatus.SEND_OK||localTransactionState!=LocalTransactionState.COMMIT_MESSAGE){
           throw new GlobalException("订单发送事务消息失败");
       }
    }

    /**
     * 保存子订单
     */
    private void saveCourseOrderItem(Course course,CourseOrder courseOrder,CourseOrderItem courseOrderItem,CourseMarket courseMarket,Date date) {
        //对应秒杀订单
        courseOrderItem.setOrderId(courseOrder.getId());
        //秒杀课程的价格
        courseOrderItem.setAmount(courseMarket.getPrice());
        //秒杀到课程的数量
        courseOrderItem.setCount(1);
        courseOrderItem.setCreateTime(date);
        //秒杀课程ID
        courseOrderItem.setCourseId(course.getId());
        //秒杀课程名字
        courseOrderItem.setCourseName(course.getName());
        //封面
        courseOrderItem.setCoursePic(course.getPic());
        courseOrderItem.setVersion(courseOrder.getVersion());
        courseOrderItem.setOrderNo(courseOrder.getOrderNo());
        //courseOrderItemService.insert(courseOrderItem);
    }

    /**
     * 保存主订单
     */
    private void saveCourseOrder(CourseOrder courseOrder, Date date,Long loginId, Course course) {
        //创建时间
        courseOrder.setCreateTime(date);
        //订单编号
        String orderNo = CodeGenerateUtils.generateOrderSn(loginId);
        courseOrder.setOrderNo(orderNo);
        courseOrder.setStatusOrder(0);
        courseOrder.setUserId(loginId);
        courseOrder.setTitle("【"+course.getName()+"支付订单】");
        courseOrder.setPayType(1);
        //insert(courseOrder);
    }

    /**
     * 秒杀保存订单
     *  支付保存
     * 1.参数校验做了
     * 2从redis中拿KillPreOrderParamDto数据
     * 3.token是否有效
     * 4.保存主订单表
     * 5.保存子订单表（算出总金额）
     * 6.修改主订单表的总金额
     * CourseOrder courseOrder, Date date,Long loginId, Course course主订单要的数据
     * @param dto
     * @return
     */
    @Override
    public String killPlaceOrder(KillCourseOrderParamDto dto) {
        Long loginId = 1L;
        CourseOrder courseOrder = new CourseOrder();
        Date now = new Date();
        CourseOrderItem courseOrderItem = new CourseOrderItem();
        //2从redis中拿KillPreOrderParamDto数据
        Object preOrderParamTmp = redisTemplate.opsForValue().get(dto.getOrderNo());
        KillPreOrderParamDto preOrderParam = (KillPreOrderParamDto) preOrderParamTmp;
        KillCourse killCourse = preOrderParam.getKillCourse();
        Course course = new Course();
        course.setName(killCourse.getCourseName());
        course.setId(killCourse.getCourseId());
        course.setPic(killCourse.getCoursePic());
        CourseMarket courseMarket = new CourseMarket();
        courseMarket.setPrice(killCourse.getKillPrice());
        //3.token是否有效
        String key = loginId+":"+killCourse.getCourseId();
        Object tokenTmp = redisTemplate.opsForValue().get(key);
        AssertUtil.isNotNull(tokenTmp,"token失效");
        AssertUtil.isEquals(dto.getToken(),tokenTmp.toString(),"token不匹配，请重试");
        //4.保存主订单表
        saveCourseOrder(courseOrder,now,loginId,course);
        //5.保存子订单表(算出总金额)要的数据
        // Course course,CourseOrder courseOrder,CourseOrderItem courseOrderItem,CourseMarket courseMarket,Date date
        saveCourseOrderItem(course,courseOrder,courseOrderItem,courseMarket,now);
        return dto.getOrderNo();
    }





}
